﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WebNext.Domain.Entities;
using WebNext.Domain.Interfaces;
using NHibernate;
using NHibernate.Linq;

namespace WebNext.DataAccess.Repositories
{
	public class EntriesRepository : EntitiesRepository<Entry>, IEntriesRepository
	{
		public CultureId CultureId
		{
			get;
			set;
		}

		public EntriesRepository(IDatabaseContext databaseContext) : base(databaseContext)
		{
		}

		public IEnumerable<ArchiveInfo> GetArchives(EntryType type, bool publishedOnly)
		{
			IQueryable<Entry> query = this.databaseContext.Session.Query<Entry>().Where(e => e.Type == type && e.CultureId == this.CultureId);
			if (publishedOnly)
			{
				query = query.Where(e => e.IsPublished);
			}
			List<DateTime> dates = query.Select(e => e.CreatedOn).ToList();

			List<ArchiveInfo> archives = new List<ArchiveInfo>();
			var yearGroups = dates.GroupBy(d => (d.Year));
			foreach (var yearGroup in yearGroups.OrderByDescending(g => g.Key))
			{
				var monthGroups = yearGroup.GroupBy(g => g.Month);
				foreach (var monthGroup in monthGroups.OrderByDescending(g => g.Key))
				{
					archives.Add(new ArchiveInfo(yearGroup.Key, monthGroup.Key, monthGroup.Count()));
				}
			}
			return archives;
		}

		public virtual IEnumerable<Entry> GetArchiveEntries(EntryType type, int pageNumber, int pageSize, int year, int month, bool publishedOnly)
		{
			IQueryOver<Entry, Entry> entryQuery = this.GetArchiveEntries(type, year, month, publishedOnly);
			return entryQuery.Skip(pageNumber * pageSize).Take(pageSize).List();
		}

		public virtual int GetArchiveEntriesCount(EntryType type, int year, int month, bool publishedOnly)
		{
			IQueryOver<Entry, Entry> entryQuery = this.GetArchiveEntries(type, year, month, publishedOnly);
			return entryQuery.RowCount();
		}

		public virtual IEnumerable<Entry> GetAll(EntryType type)
		{
			return this.databaseContext.Session.QueryOver<Entry>().Where(e => e.Type == type && e.CultureId == this.CultureId).List();
		}

		public virtual IEnumerable<Entry> GetAll(EntryType type, int pageNumber, int pageSize, string tag, bool publishedOnly)
		{
			IQueryOver<Entry> entryQuery = this.GetAllQuery(type, tag, publishedOnly);
			return entryQuery.Skip(pageNumber * pageSize).Take(pageSize).List();
		}

		public virtual int GetAllCount(EntryType type, string tag, bool publishedOnly)
		{
			IQueryOver<Entry> entryQuery = this.GetAllQuery(type, tag, publishedOnly);
			return entryQuery.RowCount();	
		}

		private IQueryOver<Entry> GetAllQuery(EntryType type, string tag, bool publishedOnly)
		{
			IQueryOver<Entry, Entry> query = this.GetAllQuery(type, publishedOnly);
			IQueryOver<Entry> entryQuery = query;
			if (!string.IsNullOrEmpty(tag))
			{
				entryQuery = query.JoinQueryOver<Tag>(e => e.Tags).Where(t => t.Code == tag);
			}
			return entryQuery;
		}

		private IQueryOver<Entry, Entry> GetAllQuery(EntryType type, bool publishedOnly)
		{
			IQueryOver<Entry, Entry> query = this.databaseContext.Session.QueryOver<Entry>().Where(e => e.Type == type && e.CultureId == this.CultureId);
			if (publishedOnly)
			{
				query = query.Where(e => e.IsPublished);
			}
			return query.OrderBy(e => e.CreatedOn).Desc;
		}

		private IQueryOver<Entry, Entry> GetArchiveEntries(EntryType type, int year, int month, bool publishedOnly)
		{
			IQueryOver<Entry, Entry> entryQuery = this.GetAllQuery(type, publishedOnly);

			DateTime startDate = new DateTime(year, month, 1);
			DateTime endDate = startDate.AddMonths(1);

			return entryQuery.Where(e => e.CreatedOn >= startDate && e.CreatedOn < endDate);
		}
	}
}
